#include "TestState.h"

TestState TestState::m_TestState;
b2World* TestState::world;
std::vector<TestEntity*> TestState::EntityList;
MyContactListener myContactListenerInstance;

sf::Color buttonColor = sf::Color::White;

sf::Vector2i initialPosition = sf::Vector2i(0,0);
sf::Vector2i boxSize;

float edit_X;
float edit_Y;
float edit_Angle;

float timeStep = 1/30.0;      //the length of time passed to simulate (seconds)
int velocityIterations = 8;   //how strongly to correct velocity
int positionIterations = 3;   //how strongly to correct position

int index;

void TestState::Init(sf::RenderWindow& window)
{

    bool playerON = 1;
    selectedEntity = NULL;

    // +++ B2WORLD +++
    b2Vec2 GRAVITY(0.0, 9.8);
    world = new b2World(GRAVITY);
    world->SetContactListener(&myContactListenerInstance);

    // +++ VIEWS +++
    view.setCenter(window.getSize().x / 2, window.getSize().y / 2);
    view.setSize(window.getSize().x, window.getSize().y);
    view2.setCenter(window.getSize().x / 2, window.getSize().y / 2);
    view2.setSize(window.getSize().x, window.getSize().y);
    window.setView(view);

    //   +++ TEXT +++
    text.setPosition(sf::Vector2f(window.getSize().x -200 ,10));

    //  +++ BACKGROUND IMAGE +++
    bg.loadFromFile("resources/background.jpg");
    background.setTexture(bg);

    //  +++ SINGBLOCKS +++
    /*
    EntityList.push_back(new SingBlock(EDGE, sf::Vector2f(250,300), sf::Vector2f(50,20),40));
    SingBlock* s = new SingBlock(EDGE, sf::Vector2f(450,400), sf::Vector2f(50,20),-40);
    s->setPitch(1.5);
    EntityList.push_back(s);
    s = new SingBlock(EDGE, sf::Vector2f(250,550), sf::Vector2f(50,20),40);
    s->setPitch(.7);
    EntityList.push_back(s);
    */

    //   +++ PLAYER +++
    //playerON must be set to true at the top of this function
    if(playerON){
        //player = new Player(BOX, sf::Vector2f(350,350), "resources/walkingman2-a.png");
        player = new Player(world, BOX, sf::Vector2f(350,350), "resources/front.png");
        EntityList.push_back(player);
        player->toggleAnimated();
        player->setDimensions(0.6, 0.5);
        player->setFrameRate(20);
        player->setCurrentFrame(0);
        cameraCentered = true;
    }else{
        player = NULL;
    }

    // +++ TGUI Stuff +++

    gui.setWindow(window);
    gui.setGlobalFont("resources/arial.ttf");

    //child window
    tgui::ChildWindow::Ptr cWindow(gui);
    cWindow->load("resources/Black.conf");
    cWindow->setSize(700,150);
    cWindow->setTitle("Widget Toolbar");
    cWindow->setPosition(50,500);

    //Return to menu button
    tgui::Button::Ptr button2(gui);
    button2->load("resources/Black.conf");
    button2->setSize(150, 25);
    button2->setPosition(25, 50);
    button2->setText("Return to Menu");
    button2->bindCallback(tgui::Button::LeftMouseClicked);
    button2->setCallbackId(2);
    button2->setTextColor(buttonColor);

    // 'Doomed' checkbox
    tgui::Checkbox::Ptr checkbox(*cWindow);
    checkbox->load("resources/Black.conf");
    checkbox->setSize(30,30);
    checkbox->setPosition(500, 10);
    checkbox->setText("Doomed");
    checkbox->bindCallback(tgui::Button::LeftMouseClicked);
    checkbox->setCallbackId(3);
    checkbox->setTextColor(buttonColor);
    c2 = checkbox;

    // EditBox1 - X coordinate
    tgui::EditBox::Ptr editBox1(*cWindow);
    editBox1->load("resources/Black.conf");
    editBox1->setSize(50,30);
    editBox1->setPosition(200, 10);
    editBox1->bindCallback(tgui::Button::LeftMouseClicked);
    editBox1->setCallbackId(5);
    editBox1->setText("10");
    c3 = editBox1;

    // EditBox2 - Y coordinate
    tgui::EditBox::Ptr editBox2(*cWindow);
    editBox2->load("resources/Black.conf");
    editBox2->setSize(50,30);
    editBox2->setPosition(270, 10);
    editBox2->bindCallback(tgui::Button::LeftMouseClicked);
    editBox2->setCallbackId(6);
    editBox2->setText("10");
    c4 = editBox2;

    // EditBox3 - Rotation
    tgui::EditBox::Ptr editBox3(*cWindow);
    editBox3->load("resources/Black.conf");
    editBox3->setSize(50,30);
    editBox3->setPosition(340, 10);
    editBox3->bindCallback(tgui::Button::LeftMouseClicked);
    editBox3->setCallbackId(7);
    editBox3->setText("0");
    c5 = editBox3;

    // Widget Selector Combo Box
    tgui::ComboBox::Ptr comboBox(*cWindow);
    comboBox->load("resources/Black.conf");
    comboBox->setSize(cWindow->getSize().x * .25 ,25);
    comboBox->setPosition( 10, 10);
    comboBox->bindCallback(tgui::Button::LeftMouseClicked);
    comboBox->setCallbackId(4);
    comboBox->setTextColor(sf::Color::Green);
    comboBox->addItem("Texture Box");
    comboBox->addItem("Mario");
    comboBox->addItem("Edge");
    comboBox->addItem("Emitter");
    comboBox->addItem("SingBlock");
    comboBox->setSelectedItem(0);
    c1 = comboBox;

    //  +++ FLOOR   ++++
    EntityList.push_back(new TestEntity(world, EDGE, sf::Vector2f(400 ,600), sf::Vector2f(800,5)));
}

void TestState::Cleanup()
{

}

void TestState::Pause()
{

}

void TestState::Resume()
{

}

// +++ EVENTS ++++
void TestState::Events(GameEngine* game, sf::RenderWindow& window)
{


        //move object right with right key
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){

            if (player){
                if(player->getBody()->GetLinearVelocity().x < velocityLimit){
                    player->setDirection(false);
                    player->forceMove(b2Vec2(speedFactor,0));
                }
            }
        }

        //pressing up on keyboard moves view up
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
            //view.move(0,-5);
            scale += .01;
            if (player) player->setDimensions(scale);
        }

        //pressing down the keyboard moves view down
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
            //view.move(0,5);
            scale -= 0.01;
            if (player) player->setDimensions(scale);
        }

        //move man right with left button
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
            if (player) {
                if(player->getBody()->GetLinearVelocity().x > -velocityLimit){
                    player->setDirection(true);
                    player->forceMove(b2Vec2(-speedFactor,0));
                }
            }
        }

        window.setView(view2);
        while (window.pollEvent(event)){

            gui.handleEvent(event);

            // The callback loop
            tgui::Callback callback;
            while (gui.pollCallback(callback)){

                // Return to introState
                if (callback.id == 2){
                    game->ChangeState(IntroState::Instance() );
                }
            }

            // +++ SINGLE MOUSE CLICK +++
            if (event.type == sf::Event::MouseButtonPressed){

                // get mouse x,y in world coordinates (view)
                window.setView(view);
                sf::Vector2i windowPos = sf::Mouse::getPosition(window);
                sf::Vector2f mouseWorldPos = window.mapPixelToCoords(windowPos);

                //Right click
                if(event.mouseButton.button == sf::Mouse::Right){
                    window.setView(view);
                    sf::Vector2i windowPos = sf::Mouse::getPosition(window);
                    sf::Vector2f mouseWorldPos = window.mapPixelToCoords(windowPos);

                    index = c1->getSelectedItemIndex();
                    TestEntity* t;
                    Emitter* emTemp;
                    SingBlock* s;

                    //Get the X and Y float values from the EditBox 1 (c_1) & EditBox 2 (c_2)
                    std::string s1 = c3->getText();
                    std::string s2 = c4->getText();
                    std::string s_angle = c5->getText();
                    const char * c_2 = s2.c_str();
                    const char * c_1 = s1.c_str();
                    const char * c_angle = s_angle.c_str();
                    edit_X = std::atof(c_1);
                    edit_Y = std::atof(c_2);
                    edit_Angle = std::atof(c_angle);

                    switch (index){

                        //Box
                        case 0:
                            t = new TestEntity(world, BOX,sf::Vector2f(mouseWorldPos.x,mouseWorldPos.y),"resources/box.png");
                            EntityList.push_back(t);
                            break;
                        //Mario
                        case 1:
                            t = new TestEntity(world, BALL,sf::Vector2f(mouseWorldPos.x,mouseWorldPos.y),"resources/mario.png",0.05);
                            if(c2->isChecked()) t->doomed = true;
                            EntityList.push_back(t);
                            break;
                        //Edge Box
                        case 2:

                            initialPosition = windowPos;
                            std::cout << "X0: " << initialPosition.x << " Y0: " << initialPosition.y << std::endl;

                            //t = new TestEntity(EDGE,sf::Vector2f(mouseWorldPos.x,mouseWorldPos.y),sf::Vector2f(edit_X,edit_Y),edit_Angle);
                            //EntityList.push_back(t);
                            break;
                        //Emitter
                        case 3:
                            for(int i =0; i < 5; i++){
                                emTemp = new Emitter(world);
                                emTemp->setPosition(b2Vec2(mouseWorldPos.x + 20*i, mouseWorldPos.y));
                                if(c2->isChecked()) emTemp->setEmittedDoom(true);
                                EmitterList.push_back(emTemp);
                            }

                            break;
                        //SingBlock
                        case 4:
                            s = new SingBlock(world, EDGE,sf::Vector2f(mouseWorldPos.x,mouseWorldPos.y) , sf::Vector2f(edit_X,edit_Y),edit_Angle);
                            s->setPitch(1.5);
                            EntityList.push_back(s);
                        default:
                            break;
                    }
                }

                //Left Click to select Entities
                if(event.mouseButton.button == sf::Mouse::Left){

                    // check all Entities - Toggle on if clicked by the mouse
                    for(int i = 0;i < EntityList.size();i++) {
                        TestEntity* t2 = EntityList[i];
                        if(t2->checkContains(mouseWorldPos)){

                            //turn selected entity on
                            t2->toggleSelected();

                            //turn off the currently selected Entity, if there is one
                            if(selectedEntity && (t2 != selectedEntity)) selectedEntity->toggleSelected();

                            // set the entity as the selected entity only if the state is on
                            selectedEntity = NULL;
                            if(t2->getSelectedStatus()) selectedEntity = t2;

                            break;
                        }
                    }
                }
            }

            // +++ CONTINUOUS MOUSE CLICKS +++
            if (sf::Mouse::isButtonPressed(sf::Mouse::Left)){

            }

            //Create a box if the box is selected
            if (sf::Mouse::isButtonPressed(sf::Mouse::Right)){
                if (index == 2){
                    sf::Vector2i position2 = sf::Mouse::getPosition(window);
                    boxSize = position2 - initialPosition;
                    std::cout << "Box_X: " << boxSize.x << " Box_Y: " << boxSize.y << std::endl;
                }

            }

            //mouse button released
            if (event.type == sf::Event::MouseButtonReleased){

                if(event.mouseButton.button == sf::Mouse::Right){

                    //Create an edge
                    if(index == 2){
                        sf::Vector2i windowPos = sf::Mouse::getPosition(window);
                        sf::Vector2f mouseWorldPos = window.mapPixelToCoords(windowPos);
                        sf::Vector2f boxWorldSize = window.mapPixelToCoords((boxSize));
                        sf::Vector2f newPosition;
                        newPosition = sf::Vector2f((mouseWorldPos.x - boxWorldSize.x/2),
                                (mouseWorldPos.y - boxWorldSize.y/2));
                        std::cout << "Box_X1: " << boxSize.x << " Box_Y1: " << boxSize.y << std::endl;
                        //if(boxWorldSize.x < 0) newPosition.x += boxWorldSize.x;
                        //if(boxWorldSize.y < 0) newPosition.y += boxWorldSize.y;

                        TestEntity* t = new TestEntity(world, EDGE,newPosition,sf::Vector2f(abs(boxSize.x),abs(boxSize.y)),edit_Angle);
                        EntityList.push_back(t);
                        boxSize = sf::Vector2i(0,0);
                        std::cout << "RESET: " << "Box_X: " << boxSize.x << " Box_Y: " << boxSize.y << std::endl;
                    }

                }
            }

            //Zoom view in and out using the mouse scrollwheel
            if (event.type == sf::Event::MouseWheelMoved){
                if(event.mouseWheel.delta >= 1){
                    view.zoom(0.95f);
                }else if (event.mouseWheel.delta <= -1){
                    view.zoom(1.05f);
                }
            }

            //react to key events
            if (event.type == sf::Event::KeyPressed ){

                //apply an upward impulse to the last added body
                if (event.key.code == sf::Keyboard::Space){
                    if(player){
                        if(player->getBody()->GetLinearVelocity().y < velocityLimit){
                            player->impulseMove(b2Vec2(0,-speedFactor/2));
                        }
                    }
                }

                //Delete selected body
                if (event.key.code == sf::Keyboard::Delete){
                    if(selectedEntity){
                        ForRemoval.insert(selectedEntity);
                        selectedEntity = NULL;
                    }
                }

            }

            // Close the window and end the game when X clicked
            if (event.type == sf::Event::Closed){
                game->Quit();
            }


                window.setView(view);
        }
}

void TestState::Update(GameEngine* game, sf::RenderWindow& window)
{

        //center camera on man
        if(cameraCentered){
            view.setCenter((sf::Vector2f)player->getPixelPosition());
        }

        //advance the world
        world->Step(timeStep, velocityIterations, positionIterations);

        //update all emitters
        for(int i = 0; i != EmitterList.size(); i++){
            EmitterList[i]->Update();
        }

        //Update all entitites
        for(int i = 0;i != EntityList.size();i++) {

            TestEntity* t = EntityList[i];
            t->Update();

            //set for delete if y coordinate is over the limit
            if(t->getPixelPosition().y > yLimit && t->getType() != EDGE ) ForRemoval.insert(t);
            else if(t->eclock.getElapsedTime().asMilliseconds() > timeLimit && t-> doomed) ForRemoval.insert(t);
        }

        //Update all connectors
        for(int i = 0;i < Connector::ConnectorList.size();i++) {
            Connector::ConnectorList[i]->Update();
        }

        //calculate the FPS and display in console
        fps = 1.f / (clock.restart().asSeconds());

        //update the text string
        sf::Vector2f worldPos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
         text.setString("#Entity: " + Utility::toString(EntityList.size())
        + "\n" + "mX: " + Utility::toString(worldPos.x) + " mY: " + Utility::toString(worldPos.y)
        + "\n" + "FPS: " + Utility::toString(fps));


        //process list for deletion
          std::set<TestEntity*>::iterator it = ForRemoval.begin();
          std::set<TestEntity*>::iterator end = ForRemoval.end();
          for (; it!=end; ++it) {
              TestEntity* tempEntity = *it;

              //delete ... physics body is destroyed here
              delete tempEntity;

              //... and remove it from main list of balls
              std::vector<TestEntity*>::iterator it = std::find(EntityList.begin(),
                EntityList.end(), tempEntity);
              if ( it != EntityList.end() )
                  EntityList.erase( it );
          }

          //clear this list for next time
          ForRemoval.clear();

}

void TestState::Render(GameEngine* game, sf::RenderWindow& window)
{
        window.setView(view);

        //clear out the window, color it white
        window.clear(sf::Color::White);

        window.draw(background);

        //draw all entities
        for(int i = 0;i < EntityList.size();i++) {
            EntityList[i]->Render(window);
        }

        //draw all connectors
        for(int i = 0;i < Connector::ConnectorList.size();i++) {
            Connector::ConnectorList[i]->Render(window);
        }

        //draw the rectangle surrounding the mouse
        if (index == 2){
            sf::RectangleShape mouseRect;
            mouseRect.setPosition((sf::Vector2f)initialPosition);
            mouseRect.setSize((sf::Vector2f)boxSize);
            mouseRect.setFillColor(sf::Color::Transparent);
            mouseRect.setOutlineColor(sf::Color::Green);
            mouseRect.setOutlineThickness(2);
            window.draw(mouseRect);
        }



        window.setView(view2);

        gui.draw();
        window.draw(text);
        //window.draw(text2);

        window.display();

        window.setView(view);
}
